#ifndef __PACKAGE_MANAGER_H__
#define __PACKAGE_MANAGER_H__

#include <cstdint>
#include <set>

#include "Utils/BinaryIO.h"
#include "LiteNetLib/NetUtils.h"
#include "LiteNetLib/NetPacket.h"
#include "IFastPackage.hpp"

#include "SimpleSingleton.hpp"
#include "concurrentqueue.h"
#include "blockingconcurrentqueue.h"

using namespace LiteNetLib;

namespace PocketSurvival
{
    enum class PackageType
    {
        ServerInfo,
        ConnectionRequest,
        ConnectionReject,
        Project,
        Client,
        Pickable,
        SubsystemBody,
        SubsystemTerrain,
        SubsystemTime,
        SubsystemSky,
        SubsystemWeather,
        SubsystemElectricity,
        SubsystemPlayers,
        ComponentPlayer,
        ComponentInventory,
        ComponentVitalStat,
        ComponentClothing,
        ComponentBehavior,
        ComponentHealth,
        ComponentMount,
        ComponentSickness,
        ComponentFlu,
        ComponentOnFire,
        ComponentSleep,
        ComponentFurnace,
        PlayerData,
        Message,
        Entity,
        Projectile,
        Territoriy,
        Furniture,
        Explosion,
        MovingBlockSet,
        BlockEdit,                          // 打开某些方块或动物实体的背包，比如：箱子，熔炉，发射器
        SignBlock,

        Dispenser,
        EditableBlock,
        GroupManage,



        ModPackage = 255                   // 为后面的mod数据传输做保留

    };

    struct NetDataPackage;
    class NetPacket;
    class Client;
    class IPackage;
    
    class PackageManager : public SimpleSingletonItem
    {
        friend class SimpleSingleton;
    private:
        std::set<size_t> m_showPackageClients;
        moodycamel::ConcurrentQueue<std::shared_ptr<IPackage>> m_sendPackageQueue;

    public:
        // 基本包，就是有确定客户端的数据包(即：有 Client 对象)
        std::shared_ptr<IPackage> basePackages[256] = { nullptr };

        // 快捷包，只需要知道对应的ip地址所发送和接收的包，不需要客户端的数据传输(即：无 Client 对象)
        std::shared_ptr<IFastPackage> baseFastPackages[256] = { nullptr };
        
    public:
        void processFastPackage(net_endpoint *peeraddr, const char *buff, uint32_t buffSize, std::shared_ptr<IFastPackage> theFastPackage = nullptr);
        void processPackage(ClientPtr client, const char *buff, uint32_t buffSize);

        void addClientQueuePackage(ClientPtr client, const char *buff, uint32_t buffSize);

        void sendQueuePackage();
        inline void addSendPackageToQueue(std::shared_ptr<IPackage> package);

        void sendFastPackage(std::shared_ptr<IFastPackage> fastPackage, PacketProperty sendProperty = PacketProperty::UnconnectedMessage);
        void sendPackage(std::shared_ptr<IPackage> package);

        void registerOrReplacePackageHandle(std::shared_ptr<IPackage> packageHandle);
        void registerOrReplaceFastPackageHandle(std::shared_ptr<IFastPackage> fastPackageHandle);

        inline void addShowPackageClient(size_t addressHashCode);
        inline void clearShowPackageClient();

        void load();
        void save();


    private:
        PackageManager();
    };

    inline void PackageManager::addSendPackageToQueue(std::shared_ptr<IPackage> package)
    {
        m_sendPackageQueue.enqueue(package);
    }
    inline void PackageManager::addShowPackageClient(size_t addressHashCode)
    {
        m_showPackageClients.insert(addressHashCode);
    }
    inline void PackageManager::clearShowPackageClient()
    {
        m_showPackageClients.clear();
    }



} // namespace PocketSurvival

#endif
